package com.ctgu.zmc.stresstest.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctgu.zmc.stresstest.common.exception.MyException;
import com.ctgu.zmc.stresstest.common.utils.PageParams;
import com.ctgu.zmc.stresstest.common.utils.PageResult;
import com.ctgu.zmc.stresstest.common.utils.RedisCacheUtil;
import com.ctgu.zmc.stresstest.entity.BlogEntity;
import com.ctgu.zmc.stresstest.mapper.BlogMapper;
import com.ctgu.zmc.stresstest.service.BlogService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.ctgu.zmc.stresstest.common.contants.RedisConstants.CACHE_BLOG_KEY;
import static com.ctgu.zmc.stresstest.common.contants.RedisConstants.CACHE_BLOG_TTL;

/**
 * @author zmc
 * @description 博客业务实现类
 * @date 2023-05-28 16:03:57
 */
@Slf4j
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, BlogEntity> implements BlogService {

    private final RedisCacheUtil redisCacheUtil;

    private final RestHighLevelClient client;

    public BlogServiceImpl(RedisCacheUtil redisCacheUtil, RestHighLevelClient client) {
        this.redisCacheUtil = redisCacheUtil;
        this.client = client;
    }

    /**
     * 按博客id查询博客信息
     *
     * @param id 博客id
     * @return 博客信息
     */
    @Override
    public BlogEntity getBlogById(Long id) {
        if (id == null || id <= 0L) {
            MyException.throwException("查询失败: 博客id不能为null且必须大于0");
        }
        return this.getById(id);
    }

    /**
     * 按博客id查询博客信息---通过redis缓存
     *
     * @param id 博客id
     * @return 博客信息
     */
    @Override
    public BlogEntity getBlogByIdWithRedis(Long id) {
        if (id == null || id <= 0L) {
            MyException.throwException("查询失败: 博客id不能为null且必须大于0");
        }
        return redisCacheUtil.queryWithPassThrough(CACHE_BLOG_KEY, id, BlogEntity.class, this::getById, CACHE_BLOG_TTL, TimeUnit.SECONDS);
    }

    /**
     * 分页检索博客信息
     *
     * @param key        检索字段
     * @param pageParams 分页查询参数
     * @return List<BlogEntity>
     */
    @Override
    public PageResult<BlogEntity> queryPage(String key, PageParams pageParams) {
        LambdaQueryWrapper<BlogEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(key)) {
            queryWrapper.like(BlogEntity::getTitle, key)
                    .or().like(BlogEntity::getContent, key)
                    .or().like(BlogEntity::getType, key)
                    .or().like(BlogEntity::getNickname, key);
        }
        if (pageParams == null) {
            pageParams = new PageParams();
        }
        Page<BlogEntity> page = this.page(new Page<>(pageParams.getPageNo(), pageParams.getPageSize()), queryWrapper);
        return new PageResult<>(page);
    }

    /**
     * 分页检索博客信息---通过Elasticsearch
     *
     * @param key        检索字段
     * @param pageParams 分页查询参数
     * @return PageResult<BlogEntity>
     */
    @Override
    public PageResult<BlogEntity> queryPageWithElasticsearch(String key, PageParams pageParams) {
        if (pageParams == null) {
            pageParams = new PageParams();
        }
        // 页码
        Long pageNo = pageParams.getPageNo();
        // 页面大小
        Long pageSize = pageParams.getPageSize();

        // 1.创建SearchRequest
        SearchRequest request = new SearchRequest("stress-test");
        // 2.封装DSL查询语句
        if (StrUtil.isNotBlank(key)) {
            // 全文检索查询
            request.source().query(QueryBuilders.matchQuery("all", key));
        } else {
            // 查询所有文档
            request.source().query(QueryBuilders.matchAllQuery());
        }
        request.source()
                // 起始下标: ES中默认为0
                .from(Math.toIntExact((pageNo - 1L) * pageSize))
                // 页面大小: ES默中默认为10
                .size(Math.toIntExact(pageSize));
        // 3.发送查询请求，返回结果
        SearchResponse response = null;
        try {
            response = client.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("ES查询异常: " + e.getMessage(), e);
        }
        // 4.解析返回结果
        if (response == null) {
            return null;
        }
        SearchHits searchHits = response.getHits();
        // 4.1获取查询结果数
        long totalCount = searchHits.getTotalHits().value;
        System.err.println("共搜索到" + totalCount + "条数据");
        // 4.2获取查询结果集，进行遍历
        List<BlogEntity> blogEntityList = Arrays.stream(searchHits.getHits())
                .map(hit -> {
                    // 4.3获取Json对象
                    String blogJson = hit.getSourceAsString();
                    // 4.4手动反序列化
                    return JSONUtil.toBean(blogJson, BlogEntity.class);
                })
                .collect(Collectors.toList());
        return new PageResult<>(blogEntityList, pageNo, pageSize, totalCount);
    }

}
